package org.tony.nio.demo;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Random;

/**
 * 
 * @author tony
 * 
 */
public class FileLockDemo
{

	private static final int	SIZEOF_INT	= 4;
	private static final int	INDEX_START	= 0;
	private static final int	INDEX_COUNT	= 10;
	private static final int	INDEX_SIZE	= INDEX_COUNT * SIZEOF_INT;
	private ByteBuffer			buffer		= ByteBuffer.allocate(INDEX_SIZE);
	private IntBuffer			indexBuffer	= buffer.asIntBuffer();
	private Random				rand		= new Random();

	public static void main(String[] args) throws Exception
	{
		String fileName = "";
		boolean writer = false;
		if (args.length < 2)
		{
			System.out.println("<Usage> : java FileLockDemo [-r] [-w] fileName");
		}
		writer = args[0].equals("-w");
		fileName = args[1];

		RandomAccessFile raf = new RandomAccessFile(new File(fileName), (writer) ? "rw" : "r");

		FileChannel fc = raf.getChannel();
		FileLockDemo fld = new FileLockDemo();

		if (writer)
		{
			fld.doUpdates(fc);
		}
		else
		{
			fld.doQueries(fc);
		}
	}

	private void doQueries(FileChannel fc) throws InterruptedException
	{
		while (true)
		{

			println("<trying for shared lock ....>");

			FileLock fl = null;

			try
			{
				fl = fc.lock(INDEX_START, INDEX_SIZE, true);
				int reps = rand.nextInt(INDEX_COUNT);
				int position = INDEX_START + (reps * SIZEOF_INT);
				buffer.clear();
				fc.read(buffer, position);
				int value = indexBuffer.get(reps);

				println("<Index Entry> " + reps + "=" + value);
				Thread.sleep(100);
			}
			catch (Exception e)
			{
			}
			finally
			{
				if (fl != null)
				{
					try
					{
						fl.release();
					}
					catch (IOException e)
					{
						e.printStackTrace();
					}
				}
			}

			println("<sleeping>");
			Thread.sleep(rand.nextInt(2000) + 500);

		}
	}

	private int	idxval	= 1;

	private void doUpdates(FileChannel fc) throws IOException
	{
		indexBuffer.clear();
		for (int i = 0; i < INDEX_COUNT; i++)
		{
			idxval++;
			println("Updating index " + i + "=" + idxval);
			indexBuffer.put(idxval);
			try
			{
				Thread.sleep(500);
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}

		buffer.clear();
		fc.write(buffer, INDEX_START);
	}

	private int	lastLineLen	= 0;	// Specialized println that repaints the
									// current line

	private void println(String msg)
	{
		System.out.print("\r ");
		System.out.print(msg);
		for (int i = msg.length(); i < lastLineLen; i++)
		{
			System.out.print(" ");
		}
		System.out.print("\r");
		System.out.flush();
		lastLineLen = msg.length();
	}

}
